package za.org.meraka.chi;

//
// a simple addition practice bot
//
import java.util.*;
import java.io.*;
 
import android.app.Activity;
//
// these imports are for XMPP
//
import org.jivesoftware.smack.SmackAndroid;
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterListener;
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.packet.Presence;;
import org.jivesoftware.smack.ChatManagerListener;
import org.jivesoftware.smack.filter.IQTypeFilter;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.RosterPacket;
import org.jivesoftware.smack.filter.PacketFilter;

import org.jivesoftware.smack.util.PacketParserUtils;

import org.jivesoftware.smackx.workgroup.user.Workgroup;
import org.jivesoftware.smackx.workgroup.user.QueueListener;
import org.jivesoftware.smackx.workgroup.WorkgroupInvitationListener;
import org.jivesoftware.smackx.workgroup.WorkgroupInvitation;
import org.jivesoftware.smackx.workgroup.settings.WorkgroupProperties;
import org.jivesoftware.smackx.workgroup.agent.AgentRoster;
import org.jivesoftware.smackx.workgroup.agent.AgentRosterListener;
import org.jivesoftware.smackx.Form;
import org.jivesoftware.smackx.packet.DataForm;
import org.jivesoftware.smackx.FormField;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.muc.InvitationListener;
import org.jivesoftware.smackx.muc.HostedRoom;
import org.jivesoftware.smackx.muc.DiscussionHistory;
 
public class WorkGroupChat implements WorkgroupInvitationListener, InvitationListener,
				      RosterListener,
				      PacketListener, PacketFilter {


  
    ChiChatConfig chatConfig;

    Chi chi;

    
 
    //
    // the actual connection
    //
    XMPPConnection connection;

    //
    //
    //
    Workgroup workgroup = null;

    //
    // the agent roster for the workgroup
    //
    //AgentRoster agentRoster = null;

    //
    //
    //
    Roster roster = null;

    //
    //
    //
    MultiUserChat multiUserChat = null;

    //
    //
    // 
    MultiUserChat conferenceRoom = null;


    String status = "not started";

    public String getStatus() {
	return status; // + workgroup.getLB();
    }

    public void resetStatus() {
	status =new String();
    }
 
    public WorkGroupChat(ChiChatConfig chatConfig, Chi activity) {
	try {
		this.chatConfig = chatConfig;
		chi = activity;
	}
	catch ( Throwable t) {
		status=status.concat(" throwing " + t);
	}
    }

    public void sendMessage(String msg, boolean groupChatShowing) {
	try {
		if ( groupChatShowing)
			conferenceRoom.sendMessage(msg);
		else
			multiUserChat.sendMessage(msg);
	}
	catch ( Throwable t ) {
		status = new String("send message throwing " + t + " multiUserChat=" + multiUserChat + " msg=" + msg);
		
	}
    }

    //
    // login to an xmpp server
    //
    public boolean login() {
	boolean loggedIn = false;
	//
	// try to make a connection to the server
	//
	try {
		//
		// create a configuration to access an
		// xmpp server
		//
		// this currently connects to google
    		ConnectionConfiguration config = new 
			ConnectionConfiguration(chatConfig.getServer(), 
						new Integer(chatConfig.getPort()), 
					        chatConfig.getServer());
	
		//
		// connect to the xmpp server
		//
    		connection = new XMPPConnection(config);
	}
	catch ( Throwable t ) {
		status = status.concat("throwing " + t);
		chi.updateStatus("can't make XMPP connection " + t);
		return false;
	}

	//
	// assume connection has been made to server, now
	// try to log in
	//
	try {
	 
    		connection.connect();
	
    		connection.login(chatConfig.getUsername() + "@" + chatConfig.getServer(), 
				chatConfig.getPassword());
		
		loggedIn = true;
	}
	catch ( Throwable t ) {
		System.out.println("problems logging in " + t);
		status = status.concat(" throwing " + t);
		chi.updateStatus("can't login " + t);
	}

	//
	// if not logged in, create a new account
	//
	if ( !loggedIn ) {
		try {
			chi.updateStatus("trying to create new account");
			connection.getAccountManager().createAccount(chatConfig.getUsername(), chatConfig.getPassword());
    			connection.login(chatConfig.getUsername() + "@" + chatConfig.getServer(), chatConfig.getPassword());
			loggedIn = true;
		}
		catch ( Throwable t ) {
			System.out.println("could not create account " + t);
			chi.updateStatus("can't create new account " + t);
			return false;
		}
	}
	
	if ( !loggedIn )
		return false;
	
	connection.addPacketListener(this, this);
	Presence presence = new Presence(Presence.Type.available);
	connection.sendPacket(presence);

	roster = connection.getRoster();
	roster.addRosterListener(this);
	processRoster();

	return true;
	}

        private void processRoster() {
		Collection<RosterEntry> entries = roster.getEntries();
		Iterator<RosterEntry> iterator = entries.iterator();
		chi.updateStatus("start roster");
		while ( iterator.hasNext() ) {
			RosterEntry entry = iterator.next();
			chi.updateStatus("*");
			/*
			if ( entry.getUser().startsWith(
				chatConfig.getWorkgroup() +
                                        "@workgroup." + chatConfig.getServer()) ) {
			}
			*/
			chi.updateStatus(entry.toString());
		}
		chi.updateStatus("end roster");
        }

	public void joinWorkgroupAndConference() {
		joinWorkGroup();
		joinConference();
	}

	public void joinWorkGroup() {
		
	try {


		status=status.concat("workgroup [" + chatConfig.getWorkgroup() + "] conference[" +
			chatConfig.getConference() +"]");
		//
		// if there is no conference data, then it is a workgroup
		//
		if ( !chatConfig.getWorkgroup().trim().equals("") ) {
			workgroup = new Workgroup(chatConfig.getWorkgroup() + 
					"@workgroup." + chatConfig.getServer(), 
					connection);

			if ( workgroup.isAvailable() ) {
				workgroup.addInvitationListener(this);

				Map<String, Object> map = new HashMap<String, Object>();
				map.put("username", chatConfig.getNickname());
				workgroup.joinQueue(map, chatConfig.getUsername());
				status = new String("created Workgroup " + chatConfig.getWorkgroup());

			}
			else {
				chi.updateStatus("there is nobody available to help you");
				chi.updateConversation("status", "there is nobody available to help you", false);
				workgroup = null;
			}
		}
	}
	catch ( Throwable t ) {
		System.out.println("There are no agents available " + t);
		chi.updateStatus("there is nobody available to help you");
	}

	}

	public void joinConference() {
		try {
			
			if ( !chatConfig.getConference().trim().equals("") ) {
                        	conferenceRoom = new MultiUserChat(connection,
                                	chatConfig.getConference() + "@conference." + chatConfig.getServer());
                        	conferenceRoom.addInvitationListener(connection, this);
				DiscussionHistory history = new DiscussionHistory();
				history.setMaxStanzas(10);
                        	conferenceRoom.join(chatConfig.getNickname(), "", history, 10000);
				status = new String("created conferenceRoom " + chatConfig.getConference());
				chi.updateStatus("joined group chat");
			}
	
		}
		catch ( Throwable t ) {
			System.out.println("There are no agents available " + t);
			chi.updateStatus("There is a problem with the group chat");
		}
    }
 
    public void disconnect() {
    	connection.disconnect();
    }

 
    public void processPacket(Packet packet ) {
	if ( packet instanceof Message ) {
		Message message = (Message) packet;
		status = new String("msgtype " + message.getType());
		if ( message.getType() == Message.Type.groupchat )  {
			System.out.println(message.getBody());
			status = status.concat("@@@" + message.getBody());
			String from = message.getFrom();
			int pos = from.indexOf("/");
			String fromPrefix = from.substring(1, pos);
			String tmp = new String("unknown");
			if ( pos != -1 )
				tmp = from.substring(pos+1);
			if ( message.getFrom().startsWith(chatConfig.getConference() + "@conference." + chatConfig.getServer()) )
				chi.updateConversation(/*"3-" +*/ tmp, message.getBody(), true);
			else
				chi.updateConversation(/*"4-" +*/ tmp, message.getBody(), false);
			
		}
		/*
		if ( message.getType() == Message.Type.normal ) {
			status = status.concat(" NORMAL " + message.getBody() + " " + workgroup.getLB());
		}
		if ( message.getType() == Message.Type.error ) {
			String from = message.getFrom();
			int pos = from.indexOf("/");
			String tmp = new String("unknown");
			if ( pos != -1 )
				tmp = from.substring(pos+1);
			chi.updateConversation(tmp, message.toXML(), true);
			status=status.concat("tmp " + tmp + " " + message.toXML());
		}
		*/
	}
	if ( packet instanceof Presence  ) {
		Presence presence = (Presence) packet;
		if ( packet.getFrom().equals( chatConfig.getWorkgroup() +
                                        "@workgroup." + chatConfig.getServer()) ) {
			chi.updateStatus("from : " + packet.getFrom() + " type: " + presence.getType());
			chi.updateStatus(packet.toXML());
			if ( presence.getType().equals(Presence.Type.available) ) {
				if ( workgroup == null )
					joinWorkGroup();
			}
			if ( presence.getType().equals(Presence.Type.unavailable) ) {
				workgroup = null;
			}
		}
	}
    }


    //
    // this is a multiUserChat invitation
    //
    public void invitationReceived(Connection connection, String room, 
			String inviter, String reason, String password,
                                Message message) {
        status = new String("invitation received room=" + room + 
			    " inviter=" + inviter +
                	    " reason=" + reason + 
			    " password=" + password + 
			    " message=" + message.toXML());
    }

    //
    // this is workgroup invitation
    //
    public void invitationReceived(WorkgroupInvitation invitation) {
	try {
		status = status.concat("\ninvitation received " + invitation.getInvitationSender());
		multiUserChat = new MultiUserChat(connection, invitation.getInvitationSender());
		multiUserChat.join(chatConfig.getNickname());
		chi.updateConversation("status", "You have been linked with somebody to help you",
				false);
		chi.updateStatus("You have been linked with somebody to help you");
	}
	catch ( Throwable t ) {
		System.out.println("invitationReceived throws " + t);
		status = new String("invitationReceived throws " + t);
	}
    }

    //
    // packet filter
    //
    public boolean accept(Packet packet) {
	/*
	if ( packet instanceof Presence  ) {
		chi.updateStatus(packet.toXML());
	}
	else
		chi.updateStatus(packet.getClass().getName());
	*/
	return true;
	/*
	
	if (  ( packet instanceof Presence) || (packet instanceof RosterPacket)  )
	     //(packet instanceof PacketParserUtils.UnparsedResultIQ) )
		return false;
	else {
		return true;
	}
	*/
    }

	//
	// RosterListener methods
	//
	public void entriesAdded(Collection<String> addresses ) {
		chi.updateStatus("added:   " + addresses.toArray());
	}

	public void entriesDeleted(Collection<String> addresses ) {
		chi.updateStatus("deleted: " + addresses.toArray());
	}

	public void entriesUpdated(Collection<String> addresses ) {
		chi.updateStatus("updated: " + addresses.toArray());
	}

        public void presenceChanged(Presence presence ) {
		chi.updateStatus("roster presence: " + presence.toXML());
	}
}

